#include "ipc/sem.h"
#include "cpu/irq.h"
#include "core/task.h"
#include "tools/list.h"


void sem_init (sem_t * sem, int init_count){
    //信号量初始化
    irq_state_t state=irq_enter_protection();

    sem->count=init_count;
    list_init(&sem->wait_list);

    irq_leave_protection(state);
};

void sem_wait (sem_t * sem){

    //等待信号
    irq_state_t state=irq_enter_protection();

    if(sem->count > 0 ){
        //有空余的令牌，可以直接执行，但是要获取这个令牌
        sem->count--;
    }else{
        //没有空余的令牌，加入到等待队列中，等待新的令牌
        task_t *current_task=get_task_current();
        task_set_block(current_task);
        list_insert_last(&sem->wait_list,&current_task->wait_node);
        task_dispatch();
    }
    
    irq_leave_protection(state);
};
void sem_notify (sem_t * sem){
    irq_state_t state=irq_enter_protection();
    // 唤醒一个正在等待的进程
    
    if(list_count(&sem->wait_list)){
        // 有正在等待的进程，唤醒他，先进先出
        list_node_t *ready_task_wait_node=list_remove_first(&sem->wait_list);
        task_t *ready_task=list_node_parent(ready_task_wait_node,task_t,wait_node);
        task_set_ready(ready_task);
        task_dispatch();
    }else{
        // 没有，放回自己的令牌
        sem->count++;
    }


    irq_leave_protection(state);
};
int sem_count (sem_t * sem){
    irq_state_t state=irq_enter_protection();

    int count=sem->count;
    irq_leave_protection(state);

    return count;
};